﻿#pragma warning(disable:4996)
#include "VectorAnalysis.h"
#include <QgsVectorLayer.h>
#include <QgsFeature.h>
#include <QgsGeometry.h>
#include <QgsSpatialIndex.h>
#include <QDialogButtonBox.h>
#include <QVBoxLayout>
#include <QComboBox.h>
#include <QLabel.h>
#include <QSpinBox.h>
#include <QFileDialog.h>
#include <QMessageBox.h>
#include <QProgressDialog.h>
#include <random>
#include <QgsProject.h>
#include <QgsField.h>
#include <QgsCategorizedSymbolRenderer.h>
#include <QgsVectorFileWriter.h>
#include <QtMath>
#include <QgsSymbol.h>

VectorAnalysis::VectorAnalysis(QgsMapCanvas* canvas, QObject* parent)
	: QObject(parent), mpMapCanvas(canvas) {
}

// 进行K值聚类分析
void VectorAnalysis::performKMeansClustering()
{
	QDialog dialog;
	dialog.resize(350, 150);
	dialog.setWindowTitle(tr("选择图层和类别数"));
	QVBoxLayout* layout = new QVBoxLayout(&dialog);

	QLabel* label = new QLabel(tr("请选择点图层："), &dialog);
	layout->addWidget(label);

	// 创建图层下拉框并获取点图层
	QComboBox* comboBox = new QComboBox(&dialog);
	for (QgsMapLayer* l : QgsProject::instance()->mapLayers().values())
	{
		if (l->type() == Qgis::LayerType::Vector && static_cast<QgsVectorLayer*>(l)->geometryType() == Qgis::GeometryType::Point)
		{
			comboBox->addItem(l->name(), l->id());
		}
	}
	layout->addWidget(comboBox);

	// 创建类别数输入框并
	QLabel* kLabel = new QLabel(tr("请输入聚类类别数："), &dialog);
	layout->addWidget(kLabel);

	QSpinBox* kSpinBox = new QSpinBox(&dialog);
	// 设置聚类类别数的范围和默认值
	kSpinBox->setRange(2, 20);
	kSpinBox->setValue(5);
	layout->addWidget(kSpinBox);

	QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
	layout->addWidget(buttonBox);

	connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
	connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);

	// 如果选择确认
	if (dialog.exec() == QDialog::Accepted)
	{
		QString layerId = comboBox->currentData().toString();
		int k = kSpinBox->value();

		// 获取选中的矢量图层
		QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(QgsProject::instance()->mapLayer(layerId));
		if (!layer)
		{
			QMessageBox::warning(nullptr, tr("错误"), tr("无法找到选择的图层。"));
			return;
		}

		// 调用K均值聚类函数
		applyKMeansClustering(layer, k);
	}
}

// 实现K均值聚类算法
void VectorAnalysis::applyKMeansClustering(QgsVectorLayer* layer, int k)
{
	// 创建进度条对话框
	QProgressDialog* progressDialog = new QProgressDialog(tr("正在进行聚类分析..."), tr("取消"), 0, 100);
	progressDialog->setWindowModality(Qt::WindowModal);
	progressDialog->resize(300, 150);
	progressDialog->setFixedSize(progressDialog->size());
	progressDialog->show();

	// 获取所有要素
	QVector<QgsFeature> features;
	QgsFeatureIterator it = layer->getFeatures();
	QgsFeature feature;
	while (it.nextFeature(feature))
	{
		features.append(feature);
	}

	if (features.size() < k)
	{
		QMessageBox::warning(nullptr, tr("错误"), tr("点的数量少于聚类的类别数。"));
		return;
	}

	// 初始化聚类中心
	QVector<QgsPointXY> centroids;
	std::default_random_engine generator;
	std::uniform_int_distribution<int> distribution(0, features.size() - 1);
	for (int i = 0; i < k; ++i)
	{
		centroids.append(features[distribution(generator)].geometry().asPoint());
	}

	QVector<int> labels(features.size(), -1);
	bool changed;

	do
	{
		changed = false;

		// 重新分配每个点的标签
		for (int i = 0; i < features.size(); ++i)
		{
			double minDist = std::numeric_limits<double>::max();
			int label = -1;

			for (int j = 0; j < k; ++j)
			{
				double dist = qSqrt(qPow(features[i].geometry().asPoint().x() - centroids[j].x(), 2) +
					qPow(features[i].geometry().asPoint().y() - centroids[j].y(), 2));
				if (dist < minDist)
				{
					minDist = dist;
					label = j;
				}
			}

			if (labels[i] != label)
			{
				labels[i] = label;
				changed = true;
			}
		}

		// 如果标签有变化，更新聚类中心
		if (changed)
		{
			QVector<int> counts(k, 0);
			centroids.fill(QgsPointXY());

			for (int i = 0; i < features.size(); ++i)
			{
				centroids[labels[i]].setX(centroids[labels[i]].x() + features[i].geometry().asPoint().x());
				centroids[labels[i]].setY(centroids[labels[i]].y() + features[i].geometry().asPoint().y());
				counts[labels[i]] += 1;
			}

			for (int j = 0; j < k; ++j)
			{
				if (counts[j] != 0)
				{
					centroids[j].setX(centroids[j].x() / counts[j]);
					centroids[j].setY(centroids[j].y() / counts[j]);
				}
			}
		}

		// 更新进度条
		progressDialog->setValue(progressDialog->value() + (changed ? 1 : 100));
		qApp->processEvents();

		if (progressDialog->wasCanceled())
		{
			return;
		}

	} while (changed);

	progressDialog->setValue(100);
	progressDialog->close();
	delete progressDialog;

	// 创建聚类结果图层
	QString newLayerName = layer->name() + "_clustered";
	QMessageBox::StandardButton reply;
	// 询问是否需要保存对话框
	reply = QMessageBox::question(nullptr, tr("保存聚类结果"), tr("是否需要保存聚类结果到文件？"),
		QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

	// 如果需要保存结果到文件则获取路径并进行保存
	if (reply == QMessageBox::Yes)
	{
		QString defaultPath = "../Results"; // 设置默认保存路径
		QString fileName = QFileDialog::getSaveFileName(nullptr, tr("保存聚类结果"), defaultPath, tr("Shapefile (*.shp)"));

		if (fileName.isEmpty())
		{
			return;
		}

		if (!fileName.endsWith(".shp"))
		{
			fileName += ".shp";
		}

		// 添加CLUSTER_ID字段
		QgsFields fields = layer->fields();
		fields.append(QgsField("CLUSTER_ID", QVariant::Int));

		// 创建新矢量图层
		QgsVectorLayer* newLayer = new QgsVectorLayer("Point?crs=" + layer->crs().authid(), newLayerName, "memory");
		newLayer->dataProvider()->addAttributes(fields.toList());  // 添加字段
		newLayer->updateFields();  // 更新字段

		// 为每个要素设置几何和属性
		QgsFeature newFeature;
		QgsAttributes attributes;
		for (int i = 0; i < features.size(); ++i)
		{
			newFeature.setGeometry(features[i].geometry());
			attributes = features[i].attributes();
			attributes.append(labels[i]);  // 添加聚类标签
			newFeature.setAttributes(attributes);
			newLayer->dataProvider()->addFeature(newFeature);  // 添加要素到新图层
		}

		// 将新矢量图层保存为shp格式
		QgsVectorFileWriter::WriterError error = QgsVectorFileWriter::writeAsVectorFormat(
			newLayer,
			fileName,
			"UTF-8",
			newLayer->crs(),
			"ESRI Shapefile"
		);

		if (error != QgsVectorFileWriter::NoError)
		{
			QMessageBox::critical(nullptr, tr("错误"), tr("无法保存聚类结果图层"));
			return;
		}

		// 加载保存的图层到当前工程
		QgsVectorLayer* savedLayer = new QgsVectorLayer(fileName, newLayerName, "ogr");
		if (savedLayer->isValid())
		{
			QgsProject::instance()->addMapLayer(savedLayer);
			mpMapCanvas->refresh();

			// 创建分类符号化渲染器
			QList<QgsRendererCategory> categories;
			for (int i = 0; i < k; ++i)
			{
				QgsSymbol* symbol = QgsSymbol::defaultSymbol(savedLayer->geometryType());
				symbol->setColor(QColor::fromHsv(i * 360 / k, 255, 255));
				categories.append(QgsRendererCategory(i, symbol, QString("Cluster %1").arg(i)));
			}

			// 应用分类符号化渲染器
			QgsCategorizedSymbolRenderer* renderer = new QgsCategorizedSymbolRenderer("CLUSTER_ID", categories);
			savedLayer->setRenderer(renderer);
			savedLayer->triggerRepaint(); // 重绘图层
		}
		else
		{
			QMessageBox::critical(nullptr, tr("错误"), tr("无法加载聚类结果图层"));
		}
	}
	// 如果用户选择不保存嗯，则只是添加图层，流程同上
	else if (reply == QMessageBox::No)
	{
		QgsVectorLayer* newLayer = new QgsVectorLayer("Point?crs=" + layer->crs().authid(), newLayerName, "memory");
		QgsFields fields = layer->fields();
		fields.append(QgsField("CLUSTER_ID", QVariant::Int));
		newLayer->dataProvider()->addAttributes(fields.toList());
		newLayer->updateFields();

		QgsFeature newFeature;
		QgsAttributes attributes;
		for (int i = 0; i < features.size(); ++i)
		{
			newFeature.setGeometry(features[i].geometry());
			attributes = features[i].attributes();
			attributes.append(labels[i]);
			newFeature.setAttributes(attributes);
			newLayer->dataProvider()->addFeature(newFeature);
		}

		QgsProject::instance()->addMapLayer(newLayer);
		mpMapCanvas->refresh();

		QList<QgsRendererCategory> categories;
		for (int i = 0; i < k; ++i)
		{
			QgsSymbol* symbol = QgsSymbol::defaultSymbol(newLayer->geometryType());
			symbol->setColor(QColor::fromHsv(i * 360 / k, 255, 255));
			categories.append(QgsRendererCategory(i, symbol, QString("Cluster %1").arg(i)));
		}

		QgsCategorizedSymbolRenderer* renderer = new QgsCategorizedSymbolRenderer("CLUSTER_ID", categories);
		newLayer->setRenderer(renderer);
		newLayer->triggerRepaint();
	}
}

// 进行按位置连接属性操作
void VectorAnalysis::performSpatialJoin()
{
	QDialog dialog;
	dialog.resize(350, 150);
	dialog.setWindowTitle(tr("选择图层进行按位置连接属性"));

	QVBoxLayout* layout = new QVBoxLayout(&dialog);

	QLabel* poiLabel = new QLabel(tr("请选择POI点图层："), &dialog);
	layout->addWidget(poiLabel);

	// 创建POI点图层下拉框并添加到布局
	QComboBox* poiComboBox = new QComboBox(&dialog);
	for (QgsMapLayer* l : QgsProject::instance()->mapLayers().values())
	{
		if (l->type() == Qgis::LayerType::Vector && static_cast<QgsVectorLayer*>(l)->geometryType() == Qgis::GeometryType::Point)
		{
			poiComboBox->addItem(l->name(), l->id());
		}
	}
	layout->addWidget(poiComboBox);

	QLabel* polygonLabel = new QLabel(tr("请选择面图层："), &dialog);
	layout->addWidget(polygonLabel);

	// 创建面图层下拉框并添加到布局
	QComboBox* polygonComboBox = new QComboBox(&dialog);
	for (QgsMapLayer* l : QgsProject::instance()->mapLayers().values())
	{
		if (l->type() == Qgis::LayerType::Vector && static_cast<QgsVectorLayer*>(l)->geometryType() == Qgis::GeometryType::Polygon)
		{
			polygonComboBox->addItem(l->name(), l->id());
		}
	}
	layout->addWidget(polygonComboBox);

	QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
	layout->addWidget(buttonBox);

	connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
	connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);

	// 如果确认要进行操作
	if (dialog.exec() == QDialog::Accepted)
	{
		// 获取选中的POI点图层ID和面图层
		QString poiLayerId = poiComboBox->currentData().toString();
		QString polygonLayerId = polygonComboBox->currentData().toString();
		QgsVectorLayer* poiLayer = dynamic_cast<QgsVectorLayer*>(QgsProject::instance()->mapLayer(poiLayerId));
		QgsVectorLayer* polygonLayer = dynamic_cast<QgsVectorLayer*>(QgsProject::instance()->mapLayer(polygonLayerId));

		if (!poiLayer || !polygonLayer)
		{
			QMessageBox::warning(nullptr, tr("错误"), tr("无法找到选择的图层。"));
			return;
		}

		// 调用实现按位置连接属性函数
		applySpatialJoin(poiLayer, polygonLayer);
	}
}

// 实现按位置连接属性函数
void VectorAnalysis::applySpatialJoin(QgsVectorLayer* poiLayer, QgsVectorLayer* polygonLayer)
{
	QgsFields fields = polygonLayer->fields();
	fields.append(QgsField("PoiId", QVariant::Int));

	// 创建新矢量图层
	QString newLayerName = polygonLayer->name() + "_joined";
	QgsVectorLayer* newLayer = new QgsVectorLayer("Polygon?crs=" + polygonLayer->crs().authid(), newLayerName, "memory");
	newLayer->dataProvider()->addAttributes(fields.toList());  // 添加字段
	newLayer->updateFields();  // 更新字段

	// 获取面图层的要素迭代器，创建poi图层空间索引
	QgsFeatureIterator polygonIt = polygonLayer->getFeatures();
	QgsFeature polygonFeature;
	QgsSpatialIndex poiIndex(poiLayer->getFeatures());

	// 遍历面图层的要素
	while (polygonIt.nextFeature(polygonFeature))
	{
		QgsGeometry polygonGeom = polygonFeature.geometry();

		// 查找与面要素相交的POI要素ID
		QList<QgsFeatureId> intersectedPoiIds = poiIndex.intersects(polygonGeom.boundingBox());

		bool found = false;
		for (const QgsFeatureId& id : intersectedPoiIds)
		{
			QgsFeature poiFeature;
			QgsFeatureIterator poiIt = poiLayer->getFeatures(QgsFeatureRequest().setFilterFid(id));
			if (poiIt.nextFeature(poiFeature))
			{
				// 如果找到相交的POI要素，创建新的面要素并添加到新图层
				if (polygonGeom.contains(poiFeature.geometry()))
				{
					QgsFeature newFeature(polygonFeature);
					newFeature.setFields(fields, true);
					newFeature.setAttribute("PoiId", poiFeature.id());
					newLayer->dataProvider()->addFeature(newFeature);
					found = true;
					break;
				}
			}
		}
		// 如果没有找到相交的POI要素，创建新的面要素并添加到新图层
		if (!found)
		{
			QgsFeature newFeature(polygonFeature);
			newFeature.setFields(fields, true);
			newFeature.setAttribute("PoiId", QVariant());
			newLayer->dataProvider()->addFeature(newFeature);
		}
	}

	// 询问用户是否保存连接结果到文件
	QMessageBox::StandardButton reply;
	reply = QMessageBox::question(nullptr, tr("保存连接结果"), tr("是否需要保存连接结果到文件？"),
		QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

	if (reply == QMessageBox::Yes)
	{
		QString defaultPath = "../Results"; // 设置默认保存路径
		QString fileName = QFileDialog::getSaveFileName(nullptr, tr("保存连接结果"), defaultPath, tr("Shapefile (*.shp)"));

		if (fileName.isEmpty())
		{
			return;
		}

		// 保存为shp文件
		QgsVectorFileWriter::WriterError error = QgsVectorFileWriter::writeAsVectorFormat(
			newLayer,
			fileName,
			"UTF-8",
			newLayer->crs(),
			"ESRI Shapefile"
		);

		if (error != QgsVectorFileWriter::NoError)
		{
			QMessageBox::critical(nullptr, tr("错误"), tr("无法保存连接结果图层"));
			return;
		}

		// 加载保存的图层到当前工程中
		QgsVectorLayer* savedLayer = new QgsVectorLayer(fileName, newLayerName, "ogr");
		if (savedLayer->isValid())
		{
			QgsProject::instance()->addMapLayer(savedLayer);
			mpMapCanvas->refresh();
		}
		else
		{
			QMessageBox::critical(nullptr, tr("错误"), tr("无法加载连接结果图层"));
		}
	}
	// 若选择不保存则直接将新图层添加到画布
	else if (reply == QMessageBox::No)
	{
		QgsProject::instance()->addMapLayer(newLayer);
		mpMapCanvas->refresh();
	}
}

